//
//  CrashViewController.m
//  DebugDemo
//
//  Created by XFB on 2018/11/8.
//  Copyright © 2018年 ZhouCheng. All rights reserved.
//

#import "CrashViewController.h"
#import "Person.h"

@interface CrashViewController ()
@property (weak, nonatomic) IBOutlet UILabel *conclusionLabel;

@end

@implementation CrashViewController

- (void)viewDidLayoutSubviews
{
    self.view.backgroundColor = [UIColor whiteColor];
    self.navigationItem.title = self.titleString;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setupBasicSet];
    [self setupUI];
}

- (void)setupBasicSet
{
    NSString *string = @"1.数组的增删改查问题 \n2.NSAttributedString的问题 \n3.unrecognized selector 未识别方法奔溃                                \n4.字典key、value为nil的时候 \n5.对象提前释放，指针变成了野指针";
    self.conclusionLabel.text = string;
}

- (void)setupUI
{
    /// 1.数组的 增删改查问题
//    [self test1];
    
    /// 2.NSAttributedString的问题
//    [self test2];

    /// 3.unrecognized selector 未识别方法奔溃
//    [self test3];
   
    /// 4.字典key、value为nil的时候 --- 主要出现在网络请求参数中
//    [self test4];
    
    /// 5.对象提前释放，指针变成了野指针
//    [self test5];
}

- (void)test1
{
    /// 1.取值根据索引
    NSArray *array = @[@"1", @"2", @"3"];
//    NSLog(@"%@", array[3]);
    /**
     -[__NSArrayI objectAtIndexedSubscript:]: index 3 beyond bounds [0 .. 2]
     */

    /// 2.新增插入nil
    NSMutableArray *mutableArray = @[].mutableCopy;
    [mutableArray addObject:@"1"];
    [mutableArray addObject:@"2"];
    [mutableArray addObject:@"3"];
    
//    [mutableArray addObject:nil];
//    [mutableArray insertObject:nil atIndex:1];

    NSLog(@"%@", mutableArray);
    
    /**
     上述两种情况都是因为 插入nil 造成奔溃
     -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
     */
    
    /// 3.删除
//    [mutableArray removeObjectAtIndex:4];
    
    /**
     删除的index 索引超过 数组索引范围
     -[__NSArrayM removeObjectsInRange:]: range {4, 1} extends beyond bounds [0 .. 2]'
     */
    
    /// 4.替换
//    [mutableArray replaceObjectAtIndex:5 withObject:@"123"];
//    [mutableArray replaceObjectAtIndex:2 withObject:nil];
    /**
     替换的时候 index索引超过了 数组的索引范围
     或者出现替换nil的情况
     -[__NSArrayM replaceObjectAtIndex:withObject:]: index 4 beyond bounds [0 .. 2]' index索引超过数组的范围
     -[__NSArrayM replaceObjectAtIndex:withObject:]: object cannot be nil'          替换的对象为nil
     */
    
    NSLog(@"%@", mutableArray);

    /**
     总结：
     数组的增删改查问题
     1.新增对象为nil，或者插入超过数组的范围，或者插入的值为nil
     2.删除对象索引超过数组的范围，删除不存在的对象不会崩溃，删除nil也不会报错
     3.替换对象为nil，或者替换的索引不是数组范围内
     4.取值的时候根据index超过数组范围
     
     预防方法 Runtime添加数组分类处理以上问题
     1.替换系统的方法，通过Method Swizzling替换成自己的方法，在执行方法的时候加以判断
     2.使用类扩展一个方法自定义实现对应操作后的预防
     
     */
}

- (void)test2
{
    NSString *string = nil;
//    NSRange range = NSMakeRange(3, 5);
//    NSString *string = @"123456";
    NSRange range = NSMakeRange(0, 3);
    NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithString:string];
    [attr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:20] range:range];
//    [attr addAttributes:@{ NSFontAttributeName : [UIFont systemFontOfSize:20]} range:range];
    
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(15, NavBarHeight + 20, ScreenW-30, 50)];
    label.font = [UIFont systemFontOfSize:15];
    label.attributedText = attr;
    [self.view addSubview:label];
    
    /**
     NSString *string = nil;复现
     'NSConcreteMutableAttributedString initWithString:: nil value'
     
     执行富文本处理的时候，一般都是服务器返回回来的数据，需要做空判断
     最好nil和@""的判断都加上
     */
    
    /**
     NSRange range = NSMakeRange(3, 5);复现
    'NSMutableRLEArray objectAtIndex:effectiveRange:: Out of bounds'
     
     富文本的范围越界了，最好留意下NSRange的范围
     */
}

- (void)test3
{
    UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(15, NavBarHeight + 100, ScreenW-30, 50)];
    [button setTitle:@"登录" forState:UIControlStateNormal];
    [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [button setBackgroundColor:[UIColor orangeColor]];
    [button addTarget:self action:@selector(buttonDidClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
    
    /**
     [CrashViewController buttonDidClick:]: unrecognized selector sent to instance 0x7fe8edf2b580'
     无法识别方法
     */
}

- (void)buttonDidClick
{
    NSLog(@"登录按钮点击了");
}

- (void)test4
{
    NSString *name = nil;
    /// 可在此判断
    if (![name isEqualToString:@""] && name != nil) {
        NSLog(@"name是有值的");
    }
//    NSAssert(name != nil, @"Initial dictionary key or value can't is nil");
    
    NSMutableDictionary *postParm = [NSMutableDictionary dictionary];
    [postParm setObject:name forKey:@"name"];
    [postParm setObject:@(20) forKey:@"age"];
    NSLog(@"%@", postParm);
    
    /// 新增了一种不是类方法的 __NSPlaceholderDictionary
    NSDictionary *parameter = @{@"name" : name,
                                @"age" : @(20)};
    NSLog(@"%@", parameter);
    
    
    /**
     [__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[0]'
     字典初始化的时候key或者value不能为nil，一般上传参数都需要做nil判断处理
     */
}

- (void)test5
{
    Person *person = [[Person alloc] init];
    person.name = @"汤姆";
    
    __weak typeof(person) weakPerson = person;
    person.personBlock = ^{
        
        __strong typeof(weakPerson) strongPerson = weakPerson;
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@", strongPerson.name);
            /// (null)
        });
    };
    person.personBlock();

    
    /**
     对象打印为（null）
     需要加上 __strong typeof(weakPerson) strongPerson = weakPerson;
     
     不然对象提前释放了
     */
    
}



@end
